﻿using System;

namespace Log
{
    /// <summary>
    /// Classe padrão para registros de log
    /// </summary>
    public sealed class RegistrarLog
    {
        private static readonly RegistrarLog log = new RegistrarLog();

        private RegistrarLog()
        {
            LogTipo = GrauCritico.Erro;
        }
        
        /// <summary>
        /// Inicia o processo de log.
        /// </summary>
        public static RegistrarLog Instanciar
        {
            get { return log; }
        }

        private GrauCritico _logTipo;
        private bool _sucesso;
        private bool _informacao;
        private bool _alerta;
        private bool _falha;
        private bool _erro;
        private bool _erroCritico;
        private bool _debug;

        /// <summary>
        /// Definição do tipo de log a ser gerado.
        /// </summary>
        public GrauCritico LogTipo 
        { 
            get { return _logTipo; }
            set 
            { 
                _logTipo = value; 
                
                _sucesso = GrauCritico.Sucesso == _logTipo;
                _informacao = GrauCritico.Informacao == _logTipo;
                _alerta = GrauCritico.Alerta == _logTipo;
                _falha = GrauCritico.Falha == _logTipo;
                _erro = GrauCritico.Erro == _logTipo;
                _erroCritico = GrauCritico.ErroCritico == _logTipo;
                _debug = GrauCritico.Debug == _logTipo;
            }
        }

        #region Registros por tipo de log

        /// <summary>
        /// Registra um log de debug sem definição de exceção.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Debug(string mensagem, out int ret)
        {
            int retorno = 0;
            if (_debug)
                Debug(mensagem, null, out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de debug com especificação da exceção ocorrida.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="exception">Exceção ocorrida na execução do programa</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Debug(string mensagem, Exception exception, out int ret)
        {
            int retorno = 0;
            if (_debug)
                OnLog(new EventosLogEventArgs(GrauCritico.Debug, mensagem, exception, DateTime.Now), out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de sucesso sem definição de exceção.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Sucesso(string mensagem, out int ret)
        {
            int retorno = 0;
            if (_sucesso)
                Sucesso(mensagem, null, out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de sucesso com especificação da exceção ocorrida.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="exception">Exceção ocorrida na execução do programa</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Sucesso(string mensagem, Exception exception, out int ret)
        {
            int retorno = 0;
            if (_sucesso)
                OnLog(new EventosLogEventArgs(GrauCritico.Sucesso, mensagem, exception, DateTime.Now), out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de informações sem definição de exceção.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Informacao(string mensagem, out int ret)
        {
            int retorno = 0;
            if (_informacao)
                Informacao(mensagem, null, out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de informações com especificação da exceção ocorrida.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="exception">Exceção ocorrida na execução do programa</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Informacao(string mensagem, Exception exception, out int ret)
        {
            int retorno = 0;
            if (_informacao)
                OnLog(new EventosLogEventArgs(GrauCritico.Informacao, mensagem, exception, DateTime.Now), out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de alerta sem definição de exceção.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Alerta(string mensagem, out int ret)
        {
            int retorno = 0;
            if (_alerta)
                Informacao(mensagem, null, out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de alerta com especificação da exceção ocorrida.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="exception">Exceção ocorrida na execução do programa</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Alerta(string mensagem, Exception exception, out int ret)
        {
            int retorno = 0;
            if (_alerta)
                OnLog(new EventosLogEventArgs(GrauCritico.Alerta, mensagem, exception, DateTime.Now), out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de falha sem definição de exceção.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Falha(string mensagem, out int ret)
        {
            int retorno = 0;
            if (_falha)
                Informacao(mensagem, null, out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de falha com especificação da exceção ocorrida.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="exception">Exceção ocorrida na execução do programa</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Falha(string mensagem, Exception exception, out int ret)
        {
            int retorno = 0;
            if (_falha)
                OnLog(new EventosLogEventArgs(GrauCritico.Falha, mensagem, exception, DateTime.Now), out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de erro sem definição de exceção.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Erro(string mensagem, out int ret)
        {
            int retorno = 0;
            if (_erro)
                Erro(mensagem, null, out retorno);
            ret = retorno;
        }
        
        /// <summary>
        /// Registra um log de erro com especificação da exceção ocorrida.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="exception">Exceção ocorrida na execução do programa</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void Erro(string mensagem, Exception exception, out int ret)
        {
            int retorno = 0;
            if (_erro)
                OnLog(new EventosLogEventArgs(GrauCritico.Erro, mensagem, exception, DateTime.Now), out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de erro crítico (interrupção) sem definição de exceção.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void ErroCritico(string mensagem, out int ret)
        {
            int retorno = 0;
            if (_erroCritico)
                ErroCritico(mensagem, null, out retorno);
            ret = retorno;
        }

        /// <summary>
        /// Registra um log de erro crítico (interrupção) com especificação da exceção ocorrida.
        /// </summary>
        /// <param name="mensagem">Texto da mensagem do log a ser registrado.</param>
        /// <param name="exception">Exceção ocorrida na execução do programa</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public void ErroCritico(string mensagem, Exception exception, out int ret)
        {
            int retorno = 0;
            if (_erroCritico)
                OnLog(new EventosLogEventArgs(GrauCritico.ErroCritico, mensagem, exception, DateTime.Now), out retorno);
            ret = retorno;
        }

        #endregion

        /// <summary>
        /// Manipulador do evento de registro do log.
        /// </summary>
        /// <param name="sender">Objeto que gerou o evento.</param>
        /// <param name="e">Objeto que define o log gerado.</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        public delegate void LogEventHandler(object sender, EventosLogEventArgs e, out int ret);

        /// <summary>
        /// Objeto manipulador do log.
        /// </summary>
        public event LogEventHandler Log;

        /// <summary>
        /// Evento que inicia o registro do log, invocando seu destino e repassando para o mesmo os dados do log a ser registrado.
        /// </summary>
        /// <param name="e">Informações do log a ser registrado.</param>
        /// <param name="ret">Código de retorno para a aplicação que solicitou o registro.</param>
        private void OnLog(EventosLogEventArgs e, out int ret)
        {
            ret = 0;
            if (Log != null)
            {
                Log(this, e, out ret);
            }
        }

        /// <summary>
        /// Incorpora ao evento o construtor de uma classe de registro de log.
        /// </summary>
        /// <param name="observer">Identifica a classe de registro de log utilizada.</param>
        public void Attach(ILog observer)
        {
            Log += observer.Log;
        }

        /// <summary>
        /// Desvincula do evento a classe de registro de log.
        /// </summary>
        /// <param name="observer">Identifica a classe de registro de log que será desvinculada.</param>
        public void Detach(ILog observer)
        {
            Log -= observer.Log;
        }
    }
}
